共计 7846 个字符,预计需要花费 20 分钟才能阅读完成。
提醒:本文最后更新于 2024-07-26 10:39,文中所关联的信息可能已发生改变,请知悉!
一、修复图片测试
概述
将定位出来的噪声点用邻域内的非噪声点赋值
测试结果
阈值:6
可以看到,除了图像最边界的噪声点和部分连块较多的噪声点之外,全部能够修复
原因分析
这个问题在上周就已经发现,连块较多的部分,在噪声检测中只能检测出连块中的部分像素点
而在修改时,是用最接近的非噪声点修改的,所以,在这里未能修复
修改阈值
阈值:5
与 6 相比,阈值为 5 时,多修复了两个像素点
阈值:3
阈值为 3 时,人为噪声点全部去除,但是边缘上会出现非预期的噪声
代码示例
# python3.8
# utf-8
"""
1. 将图片缩小二分之一:取左上角的点
2. 找出噪声点:划分方法一
划分方法二
标记次数
3. 修改
找最接近的未标记过的点
"""
import cv2 as cv
import numpy as np
threshold = 6
class PixelChannel:
def __init__(self, channel, noise, row, col):
self.noise = noise
self.channel = channel
self.row = row
self.col = col
class Part:
def __init__(self, x, y, area):
self.x = x
self.y = y
self.area = area
# 将图像缩小到一半
def half(pixel_channel):
row = pixel_channel.row
col = pixel_channel.col
half_row = row // 2
half_col = col // 2
channel = np.zeros((half_row + 1, half_col + 1), dtype=type(pixel_channel.channel))
for i in range(0, row, 2):
for j in range(0, col, 2):
channel[i // 2][j // 2] = pixel_channel.channel[i][j]
result = PixelChannel(channel, noise_check(channel), half_row, half_col)
return result
# 建立像素通道类
def create_pixel_channel(img_channel):
(row, col) = img_channel.shape
result = PixelChannel(img_channel, noise_check(img_channel), row, col)
return result
# 不考虑位置
def division1(_8area):
result = [0] * 8
p1 = [_8area[0][0], _8area[0][1], _8area[0][2], _8area[1][2], _8area[2][2], _8area[2][1], _8area[2][0],
_8area[1][0]]
p = sorted(p1)
q = [abs(int(p[0]) - int(p[1])), abs(int(p[1]) - int(p[2])), abs(int(p[2]) - int(p[3])), abs(int(p[3]) - int(p[4])),
abs(int(p[4]) - int(p[5])), abs(int(p[5]) - int(p[6])), abs(int(p[6]) - int(p[7]))]
# 判断区分度
if max(q) < 10:
return result, False
max_index = q.index(max(q))
for i in range(0, max_index + 1):
result[p1.index(p[i])] = 1
for i in range(8):
if result[i] != 1:
result[i] = 2
"""
min_index = 0
for i in range(1, 8):
if p[i] < p[min_index]:
min_index = i
max_index1 = min_index
for i in range(1, 8):
if p[i] > p[max_index1]:
max_index1 = i
max_index2 = min_index
for i in range(1, 8):
if i != max_index1 and p[i] > p[max_index2]:
max_index2 = i
max_index3 = min_index
for i in range(1, 8):
if i != max_index1 and i != max_index2 and p[i] > p[max_index3]:
max_index3 = i
max_index4 = min_index
for i in range(1, 8):
if i != max_index1 and i != max_index2 and i != max_index3 and p[i] > p[max_index4]:
max_index4 = i
# 将较小的的四个标记为 1 区域,较大区域标记为 2
result[max_index1] = 2
result[max_index2] = 2
result[max_index3] = 2
result[max_index4] = 2
for i in range(8):
if result[i] != 2:
result[i] = 1
"""
return result, True
# 考虑位置
def division2(_8area):
result = [0] * 8
p = [_8area[0][0], _8area[0][1], _8area[0][2], _8area[1][2],
_8area[2][2], _8area[2][1], _8area[2][0], _8area[1][0]]
d = [int(p[0]) - int(p[1]), int(p[1]) - int(p[2]), int(p[2]) - int(p[3]), int(p[3]) - int(p[4]),
int(p[4]) - int(p[5]), int(p[5]) - int(p[6]), int(p[6]) - int(p[7]), int(p[7]) - int(p[0])]
max_index = 0
min_index = 0
for i in range(1, 8):
if d[i] > d[max_index]:
max_index = i
if d[i] < d[min_index]:
min_index = i
if max_index == min_index:
pass
elif max_index > min_index:
for i in range(0, min_index + 1):
result[i] = 1
for i in range(min_index + 1, max_index + 1):
result[i] = 2
if max_index < 7:
for i in range(max_index + 1, 8):
result[i] = 1
elif max_index < min_index:
for i in range(0, max_index + 1):
result[i] = 2
for i in range(max_index + 1, min_index + 1):
result[i] = 1
if min_index < 7:
for i in range(min_index + 1, 8):
result[i] = 2
# 判断区分度
max1 = 0
for i in range(8):
if result[i] == 1 and p[i] > max1:
max1 = p[i]
min2 = 0
for i in range(8):
if result[i] == 2 and p[i] < min2:
min2 = p[i]
if max1 - min2 < 10:
return result, False
else:
return result, True
# 一维数组映射到二维
def _1d_2_2d(x):
if x == 0:
return 0, 0
elif x == 1:
return 0, 1
elif x == 2:
return 0, 2
elif x == 3:
return 1, 2
elif x == 4:
return 2, 2
elif x == 5:
return 2, 1
elif x == 6:
return 2, 0
elif x == 7:
return 1, 0
# 特殊值处理
def special_check(_8area):
p = [_8area[0][0], _8area[0][1], _8area[0][2], _8area[1][2],
_8area[2][2], _8area[2][1], _8area[2][0], _8area[1][0]]
p_sum = int(p[0])+int(p[1])+int(p[2])+int(p[3])+int(p[4])+int(p[5])+int(p[6])+int(p[7])
max_differ = 0
max_index = 0
for i in range(8):
if abs(int(p[i]) - (p_sum - int(p[i])) // 7) > max_differ:
max_differ = abs(int(p[i]) - (p_sum - int(p[i])) // 7)
max_index = i
if max_differ > 10:
return _1d_2_2d(max_index)
else:
return -1, -1
def noise_check(img_channel):
(row, col) = img_channel.shape
result = [[0] * col for i in range(row)]
for i in range(1, row - 1):
for j in range(1, col - 1):
# _8_area = type(img_channel)
_8_area = [[0] * 3 for i in range(3)]
_8_area[0][0] = img_channel[i - 1][j - 1]
_8_area[0][1] = img_channel[i - 1][j]
_8_area[0][2] = img_channel[i - 1][j + 1]
_8_area[1][2] = img_channel[i][j + 1]
_8_area[2][2] = img_channel[i + 1][j + 1]
_8_area[2][1] = img_channel[i + 1][j]
_8_area[2][0] = img_channel[i + 1][j - 1]
_8_area[1][0] = img_channel[i][j - 1]
# 不考虑位置
part1, flag1 = division1(_8_area)
# 考虑位置
part2, flag2 = division2(_8_area)
if flag1 == False or flag2 == False:
continue
# 处理特殊值
sx, sy = special_check(_8_area)
if sx != -1:
result[i - 1 + sx][j - 1 + sy] += 1
# 比较
for k in range(8):
if part1[k] != part2[k]:
x, y = _1d_2_2d(k)
result[i - 1 + x][j - 1 + y] += 1
return result
# 不考虑缩小二分之一图像
def mark(pixel_channel):
for i in range(pixel_channel.row):
for j in range(pixel_channel.col):
if pixel_channel.noise[i][j] >= 6:
pixel_channel.channel[i][j] = 0
return pixel_channel
# 找到最合适的值
def find_best(pixel_channel, x, y):
p = pixel_channel.channel[x][y]
# 建立领域列表
neighborhood = []
if pixel_channel.row > x-1 >= 0 and pixel_channel.col > y-1 >= 0 and pixel_channel.noise[x-1][y-1] < threshold:
neighborhood.append(pixel_channel.channel[x-1][y-1])
if pixel_channel.row > x-1 >= 0 and pixel_channel.col > y >= 0 and pixel_channel.noise[x-1][y] < threshold:
neighborhood.append(pixel_channel.channel[x-1][y])
if pixel_channel.row > x-1 >= 0 and pixel_channel.col > y+1 >= 0 and pixel_channel.noise[x-1][y+1] < threshold:
neighborhood.append(pixel_channel.channel[x-1][y+1])
if pixel_channel.row > x >= 0 and pixel_channel.col > y+1 >= 0 and pixel_channel.noise[x][y+1] < threshold:
neighborhood.append(pixel_channel.channel[x][y+1])
if pixel_channel.row > x+1 >= 0 and pixel_channel.col > y+1 >= 0 and pixel_channel.noise[x+1][y+1] < threshold:
neighborhood.append(pixel_channel.channel[x+1][y + 1])
if pixel_channel.row > x+1 >= 0 and pixel_channel.col > y >= 0 and pixel_channel.noise[x+1][y] < threshold:
neighborhood.append(pixel_channel.channel[x+1][y])
if pixel_channel.row > x+1 >= 0 and pixel_channel.col > y-1 >= 0 and pixel_channel.noise[x+1][y-1] < threshold:
neighborhood.append(pixel_channel.channel[x+1][y-1])
if pixel_channel.row > x >= 0 and pixel_channel.col > y-1 >= 0 and pixel_channel.noise[x][y-1] < threshold:
neighborhood.append(pixel_channel.channel[x][y-1])
# 搜索与给定点最接近的非噪声点
# 建立差值列表
d = []
for i in range(len(neighborhood)):
d.append(abs(int(neighborhood[i])-int(p)))
min_index = d.index(min(d))
return neighborhood[min_index]
# 考虑缩小二分之一图像
def repair(pixel_channel, half_channel):
for i in range(half_channel.row):
for j in range(half_channel.col):
if half_channel.noise[i][j] >= 6:
# pixel_channel.channel[i*2][j*2] = 0
# 若检测出为噪声,则将原图中的点的噪声值增加(至少大于阈值)pixel_channel.noise[i*2][j*2] += 10
for i in range(pixel_channel.row):
for j in range(pixel_channel.col):
if pixel_channel.noise[i][j] >= 6:
pixel_channel.channel[i][j] = find_best(pixel_channel, i, j)
return pixel_channel
def main():
# 图像地址
img_address = "img_noise.png"
# 以 BGR 方式读入图像
img = cv.imread(img_address, 1)
cv.imshow("img_noise.png", img)
# 通道分离
channel_b, channel_g, channel_r = cv.split(img)
# 建立像素通道类
b = create_pixel_channel(channel_b)
g = create_pixel_channel(channel_g)
r = create_pixel_channel(channel_r)
# 缩小二分之一
half_b = half(b)
half_g = half(g)
half_r = half(r)
"""
fp = open('half_b.noise.csv', 'w')
for i in range(half_b.row):
for j in range(half_b.col):
print(half_b.noise[i][j], file=fp, end='')
print(",", file=fp, end='')
print("", file=fp)
fp = open('half_b.pixel.csv', 'w')
for i in range(half_b.row):
for j in range(half_b.col):
print(half_b.channel[i][j], file=fp, end='')
print(",", file=fp, end='')
print("", file=fp)
"""
# 不考虑二分之一图像
# new_img = cv.merge((mark(b).channel, mark(g).channel, mark(r).channel))
# 考虑二分之一图像
new_img = cv.merge((repair(b, half_b).channel, repair(g, half_g).channel, repair(r, half_r).channel))
cv.imwrite("denoised_img.png", new_img)
cv.imshow("denoised_img.png", new_img)
cv.waitKey()
cv.destroyAllWindows()
if __name__ == '__main__':
main()
二、随机噪声值
概述
真实情况下,噪声不一定是白色,那么尝试人为给定随机值的噪声
代码
import cv2 as cv
import numpy as np
import random
img = cv.imread("img.png", 1)
(rows, cols, chn) = img.shape
cv.imshow("img.png", img)
# 加噪声
for i in range(100):
x = np.random.randint(0, rows)
y = np.random.randint(0, cols)
img[x, y, :] = random.randint(0, 255)
cv.imshow("noise", img)
cv.imwrite("img_noise.png", img)
cv.waitKey()
cv.destroyAllWindows()
噪声效果
噪声修复
肉眼观察,大约有五个点没有被修复
调整阈值,发现效果也没有多大改善
三、降噪对直线检测的影响
概述
这里主要测试噪声对直线检测的影响
直线检测用 Canny 算子完成
降噪前
降噪后
优化
能看到红框标记的地方有明显的优化
正文完